![TerraformがAWS SSO(Single Sign-On)に対応してました](https://devio2023-media.developers.io/wp-content/uploads/2019/05/aws-single-sign-on.png)
TerraformがAWS SSO(Single Sign-On)に対応してました
上記エントリを書いた際(2020/10/29時点)には、TerraformでAWS SSO(Single Sign-On)のリソースをプロビジョニングすることはできませんでした。が、その後terraform-provider-awsのv3.23.0、v3.24.0で一部リソースのプロビジョニングができるようになりましたので、使ってみたいと思います。
追加された Resource / Data Source
Resource
- aws_ssoadmin_account_assignment
- aws_ssoadmin_managed_policy_attachment
- aws_ssoadmin_permission_set
- aws_ssoadmin_permission_set_inline_policy
Data Source
概要
AWS SSOの設定としてはざっくりとは以下があります。(SSOのIDストアを使う場合です。外部のIDシステムを使う場合「ユーザー・グループを作る」あたりが変わるはずです。)
- SSOの有効化
- ユーザー・グループを作る
- アクセス権限セット(Permission Set)作成
- アクセス権限セット(Permission Set)にポリシーをアタッチ
- ユーザー・グループ & アカウント & アクセス権限セット紐付け(Assignment)
このうち、今回Terraformでプロビジョニングできるようになったのは下の3つの部分です。
上2つはプロビジョニングはできませんが、Data Sourceを使って参照することができます。
やってみた
前提条件
- Organization下に3アカウント作成
- SSO有効化
- SSOのユーザー・グループ作成
まで行なった状態で、以降の設定をTerraformでやってみます。
それぞれ対応するグループも作成して、ユーザーを配下に所属させています。
Terraformでやることの詳細は以下です。
- アクセス権限セット(Permission Set)を3つ作成する
- 上記アクセス権限セット(Permission Set)に適切なポリシーをアタッチする
- 各グループと各アカウントとアクセス権限セット(Permission Set)を紐付ける(Assignment) = 2グループ x 3アカウントで6個のAssignmentが必要
- アクセス権限セット(Permission Set)にインラインポリシーを追加する
このあたりのSSOの概念がわからない方は、先に以下エントリをお読みいただければ幸いです。
ではやっていきましょう。
アクセス権限セット作成
data "aws_ssoadmin_instances" "main" {} resource "aws_ssoadmin_permission_set" "main" { for_each = toset([ "AdministratorAccess", "ReadOnlyAccess" ]) name = each.value instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] }
data.aws_ssoadmin_instances
のarns
はset型なので上記のようにtolist(data.aws_ssoadmin_instances.main.arns)[0]
とする必要がある点に注意です。
アクセス権限セット(Permission Set)が作成されました。
アクセス権限セット(Permission Set)にポリシーをアタッチ
resource "aws_ssoadmin_managed_policy_attachment" "main" { for_each = aws_ssoadmin_permission_set.main instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] managed_policy_arn = "arn:aws:iam::aws:policy/${each.key}" permission_set_arn = each.value.arn }
ユーザー・グループ & アカウント & アクセス権限セット紐付け(Assignment)
data "aws_organizations_organization" "main" {} data "aws_identitystore_group" "admin" { identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0] filter { attribute_path = "DisplayName" attribute_value = "admin" } } resource "aws_ssoadmin_account_assignment" "admin" { for_each = toset(data.aws_organizations_organization.main.accounts[*].id) instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] permission_set_arn = aws_ssoadmin_permission_set.main["AdministratorAccess"].arn principal_id = data.aws_identitystore_group.admin.group_id principal_type = "GROUP" target_id = each.value target_type = "AWS_ACCOUNT" } data "aws_identitystore_group" "readonly" { identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0] filter { attribute_path = "DisplayName" attribute_value = "readonly" } } resource "aws_ssoadmin_account_assignment" "readonly" { for_each = toset(data.aws_organizations_organization.main.accounts[*].id) instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] permission_set_arn = aws_ssoadmin_permission_set.main["ReadOnlyAccess"].arn principal_id = data.aws_identitystore_group.readonly.group_id principal_type = "GROUP" target_id = each.value target_type = "AWS_ACCOUNT" }
aws_ssoadmin_account_assignment.target_id
にaws_organizations_organization
Data Sourceのaccounts[*].id
を使うことで、Organizations配下のアカウントをすべて対象にしています。
各アカウントにて、admin・readonlyグループがそれぞれ適切な権限をもってアサインされました。
インラインポリシーも使ってみる
上記のアクセス権限セット(Permission Set)にアタッチしたポリシーはAWS管理ポリシーでしたが、インラインポリシーも併せてアタッチすることができます。 特定の送信元IP以外からの操作はすべて拒否するインラインポリシーをアタッチしてみましょう。
data "aws_iam_policy_document" "deny_ip" { statement { effect = "Deny" actions = ["*"] resources = ["*"] condition { test = "NotIpAddress" variable = "aws:SourceIp" values = ["xxx.xxx.xxx.xxx/32"] } } } resource "aws_ssoadmin_permission_set_inline_policy" "main" { for_each = aws_ssoadmin_permission_set.main instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] inline_policy = data.aws_iam_policy_document.deny_ip.json permission_set_arn = each.value.arn }
admin userでログインしてみます。